<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>一次不太成功的搬砖（中）：rvest爬取法定传染病疫情月报数据 - Libido Chateau</title>
  <meta name="renderer" content="webkit" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>

<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />

<meta name="theme-color" content="#f8f5ec" />
<meta name="msapplication-navbutton-color" content="#f8f5ec">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#f8f5ec">


<meta name="author" content="迷幻主义搬砖号子" /><meta name="description" content="用rvest爬取到卫计委法定传染病疫情月报的（坑爹）附件，通过构造工作函数，并行遍历，完成提取-&gt;清理-&gt;合并，获得一个真正可用的数据合集。" /><meta name="keywords" content="法定传染病, 疫情报告, 爬虫" />


<meta name="baidu-site-verification" content="k5CktWnwfR" />
<meta name="google-site-verification" content="lO7fVN8Jm2sjiBOcR2knmNBKjtWcxS6KbuZYl2yELwA" />


<meta name="generator" content="Hugo 0.108.0 with theme even" />


<link rel="canonical" href="https://madlogos.github.io/post/infectdis_stat2/" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/manifest.json">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5">

<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

<link href="/sass/main.min.67ad89b7ca43747ca0757fa0c720e4a26dfb092d0c625a7e1f3b937263f7d48d.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css" integrity="sha256-Vzbj7sDDS/woiFS3uNKo8eIuni59rjyNGtXfstRzStA=" crossorigin="anonymous">
<link rel="stylesheet" href="/css/custom.css">


<meta property="og:title" content="一次不太成功的搬砖（中）：rvest爬取法定传染病疫情月报数据" />
<meta property="og:description" content="用rvest爬取到卫计委法定传染病疫情月报的（坑爹）附件，通过构造工作函数，并行遍历，完成提取-&gt;清理-&gt;合并，获得一个真正可用的数据合集。" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://madlogos.github.io/post/infectdis_stat2/" /><meta property="article:section" content="post" />
<meta property="article:published_time" content="2017-04-15T00:00:00+00:00" />
<meta property="article:modified_time" content="2021-05-09T21:28:26+08:00" />


<meta itemprop="name" content="一次不太成功的搬砖（中）：rvest爬取法定传染病疫情月报数据">
<meta itemprop="description" content="用rvest爬取到卫计委法定传染病疫情月报的（坑爹）附件，通过构造工作函数，并行遍历，完成提取-&gt;清理-&gt;合并，获得一个真正可用的数据合集。"><meta itemprop="datePublished" content="2017-04-15T00:00:00+00:00" />
<meta itemprop="dateModified" content="2021-05-09T21:28:26+08:00" />
<meta itemprop="wordCount" content="3962">
<meta itemprop="keywords" content="传染病,疫情报告,rvest," /><meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="一次不太成功的搬砖（中）：rvest爬取法定传染病疫情月报数据"/>
<meta name="twitter:description" content="用rvest爬取到卫计委法定传染病疫情月报的（坑爹）附件，通过构造工作函数，并行遍历，完成提取-&gt;清理-&gt;合并，获得一个真正可用的数据合集。"/>

<!--[if lte IE 9]>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
<![endif]-->

<!--[if lt IE 9]>
  <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->

</head>
<body>
  <div id="mobile-navbar" class="mobile-navbar">
  <div class="mobile-header-logo">
    <a href="/" class="logo">Libido Chateau</a>
  </div>
  <div class="mobile-navbar-icon">
    <span></span>
    <span></span>
    <span></span>
  </div>
</div>
<nav id="mobile-menu" class="mobile-menu slideout-menu">
  <ul class="mobile-menu-list">
    <a href="/">
        <li class="mobile-menu-item">首页</li>
      </a><a href="/post/">
        <li class="mobile-menu-item">归档</li>
      </a><a href="/tags/">
        <li class="mobile-menu-item">标签</li>
      </a><a href="/categories/">
        <li class="mobile-menu-item">分类</li>
      </a><a href="/about/">
        <li class="mobile-menu-item">关于</li>
      </a>
  </ul>

  


</nav>

  <div class="container" id="mobile-panel">
    <header id="header" class="header">
        <div class="logo-wrapper">
  <a href="/" class="logo">Libido Chateau</a>
</div>





<nav class="site-navbar">
  <ul id="menu" class="menu">
    <li class="menu-item">
        <a class="menu-item-link" href="/">首页</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/post/">归档</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/tags/">标签</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/categories/">分类</a>
      </li><li class="menu-item">
        <a class="menu-item-link" href="/about/">关于</a>
      </li>
  </ul>
</nav>

    </header>

    <main id="main" class="main">
      <div class="content-wrapper">
        <div id="content" class="content">
          <article class="post">
    
    <header class="post-header">
      <h1 class="post-title">一次不太成功的搬砖（中）：rvest爬取法定传染病疫情月报数据</h1>

      <div class="post-meta">
        <span class="post-time"> 2017-04-15 </span>
        <div class="post-category">
            <a href="/categories/%E6%95%B0%E6%8D%AE/"> 数据 </a>
            </div>
          <span class="more-meta"> 约 3962 字 </span>
          <span class="more-meta"> 预计阅读 8 分钟 </span>
        <span id="busuanzi_container_page_pv" class="more-meta"> <span id="busuanzi_value_page_pv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 次阅读 </span>
      </div>
    </header>

    <div class="post-toc" id="post-toc">
  <h2 class="post-toc-title">文章目录</h2>
  <div class="post-toc-content always-active">
    <nav id="TableOfContents">
  <ul>
    <li><a href="#数据提取">数据提取</a>
      <ul>
        <li><a href="#docxtractr"><code>docxtractr</code></a></li>
        <li><a href="#提取工具函数">提取工具函数</a></li>
      </ul>
    </li>
    <li><a href="#数据清理">数据清理</a>
      <ul>
        <li><a href="#值规范化">值规范化</a></li>
        <li><a href="#归并同类">归并同类</a></li>
      </ul>
    </li>
    <li><a href="#通用作图函数">通用作图函数</a></li>
  </ul>
</nav>
  </div>
</div>
    <div class="post-content">
      <h2 id="数据提取">数据提取</h2>
<p><a href="/post/infectdis_stat1/">接上篇</a></p>
<p>现在，可以着手把存储在附件里的信息结构化提取出来了。但在这之前，还有一个硬骨头要啃。</p>
<p><strong>要把图片附件识别成文本。</strong></p>
<p>首先考虑OCR。但是Abbyy Finereader似乎没有Ubuntu版本。其他一些主流工具要钱。网上找到几个免费OCR工具，试用了下，转出来一堆乱码亲妈都唔识得。一怒之下，放了个大招：</p>
<p><strong>手工录入。</strong></p>
<figure class="center"><img src="https://gh-1251443721.cos.ap-chengdu.myqcloud.com/2017/0406/no_word_to_say.jpg" width="50%"/>
</figure>
<p>这项工作很不好做，让我不禁怀疑起人生。但只有经过这样的磨练，才能对疾控系统的信息化水平有一个实操层面的认识。倘若遇到这方面的项目机会，<strong>记得要把工程预算乘以3</strong>。</p>
<p>图片方面的坑包括：</p>
<ol>
<li>有些图片附件分辨率低到了厚马赛克水准，别说OCR，钛金狗眼也认不出</li>
<li>有些表格作为OLE对象内嵌到了Word文件里，当我满怀希望点进去才发现，这个内嵌对象竟仍是个图片</li>
<li>有个别文件特别贴心地把表格割成两张图，插到了正文里</li>
</ol>
<p>满脸辛酸地处理完了这些杂碎，把doc和xls存作docx和xlsx，接下来总算能把它们当成正常的xml来处理了。</p>
<div class="admonition tip"><p class="admonition-title">资料</p>
<p>有读者留言提到，这些数据其实都可以从公共卫生信息网申请到。没错。但是作为数据公开党，我对这种公共数据管制甚至收费牟利的做法非常不屑。这根本不符合如今的时代精神。本文提到的这些结构化数据文档，都已打包存到<a href="https://gh-1251443721.cos.ap-chengdu.myqcloud.com/2017/0406/infect_dis_stat.zip">七牛云</a>。人人都可以免费用。</p>
</div>
<h3 id="docxtractr"><code>docxtractr</code></h3>
<p>docx和xlsx本质上是一堆xml文件打包到zip里。所以2007以后的MS Office文件都更好处理，解包后按xml语法抽节点信息就是。不过人上有人，懒外有懒。我是不会用XML包做通用解的，敲那么多代码手指不会痛吗？</p>
<p><strong>除非人命关天，否则莫造新轮。</strong></p>
<p>我们可用<code>docxtractr</code>处理docx，<code>readxl</code>处理xlsx，<code>readr</code>处理csv。<code>docxtractr</code>有个特别贴心的函数<code>docx_extract_tbl</code>，直接把word正文里的表格提取成data.frame，就跟<code>html_table</code>一样。</p>
<h3 id="提取工具函数">提取工具函数</h3>
<p>通过前面的苦力活，现在只剩下三种文件形态：csv、xlsx、docx。写一个通用方法来分类提取。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">docxtractr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">readxl</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">readr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">readMsoTbl</span> <span class="o">&lt;-</span> <span class="nf">function</span><span class="p">(</span><span class="n">mso.file</span><span class="p">,</span> <span class="n">header</span><span class="o">=</span><span class="kc">TRUE</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">file.type</span> <span class="o">&lt;-</span> <span class="nf">tolower</span><span class="p">(</span><span class="nf">str_replace</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">mso.file</span><span class="p">,</span> <span class="s">&#34;.+\\.([^\\.]+)$&#34;</span><span class="p">,</span> <span class="s">&#34;\\1&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="nf">if </span><span class="p">(</span><span class="n">file.type</span> <span class="o">==</span> <span class="s">&#34;csv&#34;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="nf">invisible</span><span class="p">(</span><span class="nf">read_csv</span><span class="p">(</span><span class="n">mso.file</span><span class="p">,</span> <span class="n">col_names</span><span class="o">=</span><span class="n">header</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span><span class="n">else</span> <span class="nf">if </span><span class="p">(</span><span class="n">file.type</span> <span class="o">==</span> <span class="s">&#34;docx&#34;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="n">docx</span> <span class="o">&lt;-</span> <span class="nf">invisible</span><span class="p">(</span><span class="nf">read_docx</span><span class="p">(</span><span class="n">mso.file</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="nf">docx_extract_tbl</span><span class="p">(</span><span class="n">docx</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="n">header</span><span class="o">=</span><span class="n">header</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span><span class="n">else</span> <span class="nf">if </span><span class="p">(</span><span class="n">file.type</span> <span class="o">==</span> <span class="s">&#34;xlsx&#34;</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="nf">invisible</span><span class="p">(</span><span class="nf">read_excel</span><span class="p">(</span><span class="n">mso.file</span><span class="p">,</span> <span class="n">col_names</span><span class="o">=</span><span class="n">header</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span><span class="n">else</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kc">NULL</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>然后用<code>lapply</code>跑个隐式循环，就把所有表格都以data.frame的形式提出来了，存为一个逼格李斯特(big list)。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">data</span> <span class="o">&lt;-</span> <span class="nf">lapply</span><span class="p">(</span><span class="nf">list.files</span><span class="p">(</span><span class="s">&#34;~/infectdis&#34;</span><span class="p">,</span> <span class="n">full.names</span><span class="o">=</span><span class="kc">TRUE</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">               <span class="nf">invisible</span><span class="p">(</span><span class="n">readMsoTbl</span><span class="p">))</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="数据清理">数据清理</h2>
<p>这样得到的数据虽然结构化了，但仍有很多问题。</p>
<ol>
<li>变量名都是X1, X2, &hellip;， 需要转成数据原本的表头</li>
<li>存在空行和空列</li>
<li>数值列含有缺失值和数值文本混合值</li>
<li>病名多样，比如“甲肝”和“甲型肝炎”本质上是一回事</li>
</ol>
<p>可以分几步走：重新定义表头，然后舍弃/纠正不规范数值，最后归并同类病名。</p>
<h3 id="值规范化">值规范化</h3>
<p>构造两个工作函数，然后lapply一轮就能把数值规范化：</p>
<ul>
<li><code>redefCol</code>用来规范每张表格的表头。如当前用的是X1, X2, &hellip;，就用首行替代。最后把变量名中的空格、星号都去掉</li>
<li><code>cleanTbl</code>用来去掉空列、空行，去掉“病名”列中的空格、星号、括号等，把发病数、死亡数两列的非数字字符都去掉</li>
</ul>
<div class="admonition tip"><p class="admonition-title">提示</p>
<p>由于后面要用到并行计算，所以工作函数内要么显式引用加载包<code>stringr</code>等，要么在函数前声明其所在命名空间，如<code>stringr::str_detect()</code>。</p>
</div>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="c1"># 重定义首行</span>
</span></span><span class="line"><span class="cl"><span class="n">redefCol</span> <span class="o">&lt;-</span> <span class="nf">function</span><span class="p">(</span><span class="n">df</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="c1">## Arg</span>
</span></span><span class="line"><span class="cl">    <span class="c1">##     df: data.frame</span>
</span></span><span class="line"><span class="cl">    <span class="nf">if </span><span class="p">(</span><span class="nf">all</span><span class="p">(</span><span class="nf">str_detect</span><span class="p">(</span><span class="nf">colnames</span><span class="p">(</span><span class="n">df</span><span class="p">),</span> <span class="s">&#34;[Xx]\\d&#34;</span><span class="p">))){</span>
</span></span><span class="line"><span class="cl">        <span class="nf">colnames</span><span class="p">(</span><span class="n">df</span><span class="p">)</span> <span class="o">&lt;-</span> <span class="n">df[1</span><span class="p">,</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">        <span class="n">df</span> <span class="o">&lt;-</span> <span class="n">df[2</span><span class="o">:</span><span class="nf">nrow</span><span class="p">(</span><span class="n">df</span><span class="p">),</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="nf">colnames</span><span class="p">(</span><span class="n">df</span><span class="p">)</span> <span class="o">&lt;-</span> <span class="nf">str_replace_all</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="nf">colnames</span><span class="p">(</span><span class="n">df</span><span class="p">),</span> <span class="s">&#34;\\s|\\*&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nf">return</span><span class="p">(</span><span class="n">df</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 数据整形</span>
</span></span><span class="line"><span class="cl"><span class="n">cleanTbl</span> <span class="o">&lt;-</span> <span class="nf">function</span><span class="p">(</span><span class="n">df</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="c1">## Args</span>
</span></span><span class="line"><span class="cl">    <span class="c1">##    df: data.frame</span>
</span></span><span class="line"><span class="cl">    <span class="c1">##    dop: date of publication</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># 去掉空列、空行</span>
</span></span><span class="line"><span class="cl">    <span class="n">is.colallNA</span> <span class="o">&lt;-</span> <span class="nf">sapply</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="nf">function</span><span class="p">(</span><span class="n">vec</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="nf">all</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">vec</span><span class="p">))</span> <span class="o">|</span> <span class="nf">all</span><span class="p">(</span><span class="nf">nchar</span><span class="p">(</span><span class="n">vec</span><span class="p">)</span><span class="o">==</span><span class="m">0</span><span class="p">)})</span>
</span></span><span class="line"><span class="cl">    <span class="n">is.rowallNA</span> <span class="o">&lt;-</span> <span class="nf">apply</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="nf">function</span><span class="p">(</span><span class="n">vec</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="nf">all</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">vec</span><span class="p">))</span> <span class="o">|</span> <span class="nf">all</span><span class="p">(</span><span class="nf">nchar</span><span class="p">(</span><span class="n">vec</span><span class="p">)</span><span class="o">==</span><span class="m">0</span><span class="p">)})</span>
</span></span><span class="line"><span class="cl">    <span class="n">o</span> <span class="o">&lt;-</span> <span class="n">df[</span><span class="o">!</span><span class="n">is.rowallNA</span><span class="p">,</span> <span class="o">!</span><span class="n">is.colallNA]</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 去掉首列空格，名称规范化</span>
</span></span><span class="line"><span class="cl">    <span class="n">o[[1]]</span> <span class="o">&lt;-</span> <span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace_all</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">o[[1]]</span><span class="p">,</span> <span class="s">&#34;[\\s＊\\*（）]&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 确保发病和死亡都是整数</span>
</span></span><span class="line"><span class="cl">    <span class="nf">invisible</span><span class="p">(</span><span class="nf">lapply</span><span class="p">(</span><span class="m">2</span><span class="o">:</span><span class="m">3</span><span class="p">,</span> <span class="nf">function</span><span class="p">(</span><span class="n">i</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">        <span class="n">o[[i]]</span> <span class="o">&lt;&lt;-</span> <span class="nf">as.numeric</span><span class="p">(</span><span class="n">stringr</span><span class="o">::</span><span class="nf">str_replace</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">o[[i]]</span><span class="p">,</span> <span class="s">&#34;\\D&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="n">o[[i]]</span><span class="nf">[is.na</span><span class="p">(</span><span class="n">o[[i]]</span><span class="p">)</span><span class="n">]</span> <span class="o">&lt;&lt;-</span> <span class="m">0</span>
</span></span><span class="line"><span class="cl">    <span class="p">}))</span>
</span></span><span class="line"><span class="cl">    <span class="nf">return</span><span class="p">(</span><span class="nf">as.data.frame</span><span class="p">(</span><span class="n">o</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>cleanTbl</code>函数内部用了好几个apply家族函数，可想而知肯定很慢。所以遍历data列表时，可以用一下并行计算<code>parallel</code>。</p>
<p>先要创建一个集群，利用<code>makeCluster</code>。这里声明构造4个集群，因为<code>detectCores()</code>会告诉系统，这台电脑有4核。少声明几个也无所谓。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">parallel</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">cl</span> <span class="o">&lt;-</span> <span class="nf">makeCluster</span><span class="p">(</span><span class="nf">getOption</span><span class="p">(</span><span class="s">&#34;cl.cores&#34;</span><span class="p">,</span> <span class="nf">detectCores</span><span class="p">()))</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>创建集群，就是为了用<code>parLapply</code>，这其实就是<code>lapply</code>的并行版本。原来是<code>snow</code>包里的。并行调用<code>cleanTbl</code>后，清干净的列表存为dat。尺寸上明显小了很多。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">dat</span> <span class="o">&lt;-</span> <span class="nf">parLapply</span><span class="p">(</span><span class="n">cl</span><span class="p">,</span> <span class="n">dat</span><span class="p">,</span> <span class="nf">invisible</span><span class="p">(</span><span class="n">cleanTbl</span><span class="p">))</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>dat用日期命名，然后再用一次lapply隐式循环，遍历dat的同时为每张表新增一列DOP。这里要用超赋值符&laquo;-。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">names</span><span class="p">(</span><span class="n">dat</span><span class="p">)</span> <span class="o">&lt;-</span> <span class="nf">str_replace</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nf">list.files</span><span class="p">(</span><span class="s">&#34;~/infectdis&#34;</span><span class="p">),</span> <span class="s">&#34;^(.+)\\..+$&#34;</span><span class="p">,</span> <span class="s">&#34;\\1&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">invisible</span><span class="p">(</span><span class="nf">lapply</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">dat</span><span class="p">),</span> <span class="nf">function</span><span class="p">(</span><span class="n">i</span><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="n">dat[[i]]</span><span class="o">$</span><span class="n">DOP</span> <span class="o">&lt;&lt;-</span> <span class="nf">as.Date</span><span class="p">(</span><span class="nf">names</span><span class="p">(</span><span class="n">dat</span><span class="p">)</span><span class="n">[i]</span><span class="p">)}))</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>清理完毕！最后调用<code>dplyr</code>的<code>bind_rows</code>，把这些列表中包裹的数据框提出来合并成一个大数据框。这个框就是后续分析的基础了。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">dplyr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">dat</span> <span class="o">&lt;-</span> <span class="nf">do.call</span><span class="p">(</span><span class="s">&#34;bind_rows&#34;</span><span class="p">,</span> <span class="n">dat</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="归并同类">归并同类</h3>
<p>首先，定义一个正则转化字典，然后遍历一遍，就把同类病名都归并了。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">dict</span> <span class="o">&lt;-</span> <span class="nf">data.frame</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">pattern</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;^.*甲乙丙类.*$&#34;</span><span class="p">,</span> <span class="s">&#34;甲乙类传染病小计&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;丙类传染病合计&#34;</span><span class="p">,</span> <span class="s">&#34;([甲乙丙丁戊])肝&#34;</span><span class="p">,</span> <span class="s">&#34;^未分型$|未分型肝炎&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;其他&#34;</span><span class="p">,</span> <span class="s">&#34;人感染H7N9禽流感&#34;</span><span class="p">,</span> <span class="s">&#34;布病&#34;</span><span class="p">,</span> <span class="s">&#34;钩体病&#34;</span><span class="p">,</span> <span class="s">&#34;^.*出血热.*$&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;^.*斑疹伤寒.*$&#34;</span><span class="p">,</span> <span class="s">&#34;伤寒\\+副伤寒&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="n">replace</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;合计&#34;</span><span class="p">,</span> <span class="s">&#34;甲乙类传染病合计&#34;</span><span class="p">,</span> <span class="s">&#34;丙类传染病小计&#34;</span><span class="p">,</span> <span class="s">&#34;\\1型肝炎&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;肝炎未分型&#34;</span><span class="p">,</span> <span class="s">&#34;其它&#34;</span><span class="p">,</span> <span class="s">&#34;人感染高致病性禽流感&#34;</span><span class="p">,</span> <span class="s">&#34;布鲁氏菌病&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;钩端螺旋体病&#34;</span><span class="p">,</span> <span class="s">&#34;流行性出血热&#34;</span><span class="p">,</span> <span class="s">&#34;流行性和地方性斑疹伤寒&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="s">&#34;伤寒和副伤寒&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 按行遍历dict，将dat$病名中符合&#39;pattern&#39;的，替换为&#39;replace&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nf">apply</span><span class="p">(</span><span class="n">dict</span><span class="p">,</span> <span class="m">1</span><span class="p">,</span> <span class="nf">function</span><span class="p">(</span><span class="n">vec</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nf">invisible</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">dat</span><span class="o">$</span>病名 <span class="o">&lt;&lt;-</span> <span class="nf">str_replace</span><span class="p">(</span><span class="n">dat</span><span class="o">$</span>病名<span class="p">,</span> <span class="n">vec[1]</span><span class="p">,</span> <span class="n">vec[2]</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>再然后，创建一个变量Class，标记甲、乙、丙三个分类。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="n">dat</span><span class="o">$</span><span class="n">Class</span> <span class="o">&lt;-</span> <span class="kc">NA</span>
</span></span><span class="line"><span class="cl"><span class="n">dat</span><span class="o">$</span><span class="n">Class[dat</span><span class="o">$</span>病名 <span class="o">%in%</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;霍乱&#34;</span><span class="p">,</span> <span class="s">&#34;鼠疫&#34;</span><span class="p">)</span><span class="n">]</span> <span class="o">&lt;-</span> <span class="s">&#34;甲类&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">dat</span><span class="o">$</span><span class="n">Class[dat</span><span class="o">$</span>病名 <span class="o">%in%</span> <span class="nf">c</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;病毒性肝炎&#34;</span><span class="p">,</span> <span class="s">&#34;细菌性和阿米巴性痢疾&#34;</span><span class="p">,</span> <span class="s">&#34;伤寒和副伤寒&#34;</span><span class="p">,</span> <span class="s">&#34;艾滋病&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;淋病&#34;</span><span class="p">,</span> <span class="s">&#34;梅毒&#34;</span><span class="p">,</span> <span class="s">&#34;脊髓灰质炎&#34;</span><span class="p">,</span> <span class="s">&#34;麻疹&#34;</span><span class="p">,</span> <span class="s">&#34;百日咳&#34;</span><span class="p">,</span> <span class="s">&#34;白喉&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;流行性脑脊髓膜炎&#34;</span><span class="p">,</span> <span class="s">&#34;猩红热&#34;</span><span class="p">,</span> <span class="s">&#34;流行性出血热&#34;</span><span class="p">,</span> <span class="s">&#34;狂犬病&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;钩端螺旋体病&#34;</span><span class="p">,</span> <span class="s">&#34;布鲁氏菌病&#34;</span><span class="p">,</span> <span class="s">&#34;炭疽&#34;</span><span class="p">,</span> <span class="s">&#34;流行性乙型脑炎&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;疟疾&#34;</span><span class="p">,</span> <span class="s">&#34;登革热&#34;</span><span class="p">,</span> <span class="s">&#34;新生儿破伤风&#34;</span><span class="p">,</span> <span class="s">&#34;肺结核&#34;</span><span class="p">,</span> <span class="s">&#34;传染性非典型肺炎&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;人感染高致病性禽流感&#34;</span><span class="p">,</span> <span class="s">&#34;血吸虫病&#34;</span><span class="p">,</span> <span class="s">&#34;甲型H1N1流感&#34;</span><span class="p">)</span><span class="n">]</span> <span class="o">&lt;-</span> <span class="s">&#34;乙类&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">dat</span><span class="o">$</span><span class="n">Class[dat</span><span class="o">$</span>病名 <span class="o">%in%</span> <span class="nf">c</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;流行性感冒&#34;</span><span class="p">,</span> <span class="s">&#34;流行性腮腺炎&#34;</span><span class="p">,</span> <span class="s">&#34;风疹&#34;</span><span class="p">,</span> <span class="s">&#34;急性出血性结膜炎&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">     <span class="s">&#34;麻风病&#34;</span><span class="p">,</span> <span class="s">&#34;包虫病&#34;</span><span class="p">,</span> <span class="s">&#34;丝虫病&#34;</span><span class="p">,</span> <span class="s">&#34;其它感染性腹泻病&#34;</span><span class="p">,</span> <span class="s">&#34;手足口病&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s">&#34;流行性和地方性斑疹伤寒&#34;</span><span class="p">,</span> <span class="s">&#34;黑热病&#34;</span><span class="p">)</span><span class="n">]</span> <span class="o">&lt;-</span> <span class="s">&#34;丙类&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nf">names</span><span class="p">(</span><span class="n">dat</span><span class="p">)</span> <span class="o">&lt;-</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;病名&#34;</span><span class="p">,</span> <span class="s">&#34;发病数&#34;</span><span class="p">,</span> <span class="s">&#34;死亡数&#34;</span><span class="p">,</span> <span class="s">&#34;日期&#34;</span><span class="p">,</span> <span class="s">&#34;分类&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">dat</span><span class="o">$</span>分类 <span class="o">&lt;-</span> <span class="nf">factor</span><span class="p">(</span><span class="n">dat</span><span class="o">$</span>分类<span class="p">,</span> <span class="n">levels</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span><span class="s">&#34;丙类&#34;</span><span class="p">,</span> <span class="s">&#34;乙类&#34;</span><span class="p">,</span> <span class="s">&#34;甲类&#34;</span><span class="p">))</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="通用作图函数">通用作图函数</h2>
<p>接下来我计划做一系列面积图，简单看看疫情的时间分布有什么有趣之处。但每次整形一遍，再写一堆ggplot命令是很烦人的。我盘算了下，大约要跑十几张图，如果写个通用作图函数增加代码复用性，整体来说还是合算的。</p>
<p><strong>作为码农，不光要坚定地偷懒，还要偷得值。</strong></p>
<p>简单说来，这个函数可以接过一个初步分析结果数据框，根据指定的xvar、yvar、gvar来设置<code>geom_area()</code>的<code>aes</code>参数，再套用一下HighChart的主题。这样每次做图，只需要写一行代码就完事了。</p>
<p>下面的代码是本次分析可视化的最核心部分。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-r" data-lang="r"><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">ggplot2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nf">library</span><span class="p">(</span><span class="n">ggthemes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">makeTsPlot</span> <span class="o">&lt;-</span> <span class="nf">function</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">df</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="n">unit</span><span class="o">=</span><span class="s">&#34;4 months&#34;</span><span class="p">,</span> <span class="n">xlab</span><span class="o">=</span><span class="n">xvar</span><span class="p">,</span> <span class="n">ylab</span><span class="o">=</span><span class="n">yvar</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">xvar</span><span class="o">=</span><span class="s">&#34;日期&#34;</span><span class="p">,</span> <span class="n">yvar</span><span class="o">=</span><span class="s">&#34;value&#34;</span><span class="p">,</span> <span class="n">gvar</span><span class="o">=</span><span class="s">&#34;分类&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">legend.position</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span><span class="m">0.6</span><span class="p">,</span> <span class="m">1.05</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">){</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Arg:</span>
</span></span><span class="line"><span class="cl">    <span class="c1">##    df: data.frame, source data</span>
</span></span><span class="line"><span class="cl">    <span class="c1">##    title: plot title</span>
</span></span><span class="line"><span class="cl">    <span class="c1">##    unit: a num or date_breaks</span>
</span></span><span class="line"><span class="cl">    <span class="c1">##    xlab, ylab: x-axis y-axis caption</span>
</span></span><span class="line"><span class="cl">    <span class="c1">##    xvar, yvar, gvar: var name of x, y, group</span>
</span></span><span class="line"><span class="cl">    <span class="c1">##    legend.position: a value that ggplot2::theme() accepts</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nf">if </span><span class="p">(</span><span class="nf">inherits</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">xvar]</span><span class="p">,</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;POSIXt&#34;</span><span class="p">,</span> <span class="s">&#34;Date&#34;</span><span class="p">))){</span>
</span></span><span class="line"><span class="cl">        <span class="n">breaks</span> <span class="o">&lt;-</span> <span class="nf">seq</span><span class="p">(</span><span class="nf">min</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">xvar]</span><span class="p">),</span> <span class="nf">max</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">xvar]</span><span class="p">),</span> <span class="n">unit</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">labels</span> <span class="o">&lt;-</span> <span class="nf">format</span><span class="p">(</span><span class="n">breaks</span><span class="p">,</span> <span class="s">&#34;%m\n%y&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">min.mon</span> <span class="o">&lt;-</span> <span class="nf">sort</span><span class="p">(</span><span class="nf">format</span><span class="p">(</span><span class="n">breaks</span><span class="p">,</span><span class="s">&#34;%m&#34;</span><span class="p">))</span><span class="n">[1]</span>
</span></span><span class="line"><span class="cl">        <span class="n">labels[</span><span class="o">!</span><span class="nf">str_detect</span><span class="p">(</span><span class="n">labels</span><span class="p">,</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;^&#34;</span><span class="p">,</span> <span class="n">min.mon</span><span class="p">))</span><span class="n">]</span> <span class="o">&lt;-</span> <span class="nf">format</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">breaks[</span><span class="o">!</span><span class="nf">str_detect</span><span class="p">(</span><span class="n">labels</span><span class="p">,</span> <span class="nf">paste0</span><span class="p">(</span><span class="s">&#34;^&#34;</span><span class="p">,</span> <span class="n">min.mon</span><span class="p">))</span><span class="n">]</span><span class="p">,</span> <span class="s">&#34;%m&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">labels</span> <span class="o">&lt;-</span> <span class="nf">str_replace</span><span class="p">(</span><span class="n">labels</span><span class="p">,</span> <span class="s">&#34;^0&#34;</span><span class="p">,</span> <span class="s">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span><span class="n">else</span> <span class="nf">if </span><span class="p">(</span><span class="nf">is.numeric</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">xvar]</span><span class="p">)){</span>
</span></span><span class="line"><span class="cl">        <span class="n">breaks</span> <span class="o">&lt;-</span> <span class="n">labels</span> <span class="o">&lt;-</span>
</span></span><span class="line"><span class="cl">            <span class="nf">seq</span><span class="p">(</span><span class="nf">min</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">xvar]</span><span class="p">),</span> <span class="nf">max</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">xvar]</span><span class="p">),</span> <span class="n">unit</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span><span class="n">else</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">breaks</span> <span class="o">&lt;-</span> <span class="n">labels</span> <span class="o">&lt;-</span> <span class="nf">unique</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">xvar]</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">pal</span> <span class="o">&lt;-</span> <span class="n">ggthemes_data</span><span class="o">$</span><span class="n">hc</span><span class="o">$</span><span class="n">palettes</span><span class="o">$</span><span class="n">default</span><span class="nf">[c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="m">3</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="m">4</span><span class="o">:</span><span class="m">10</span><span class="p">)</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">    <span class="nf">if </span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">pal</span><span class="p">)</span> <span class="o">&lt;</span> <span class="nf">length</span><span class="p">(</span><span class="nf">unique</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">gvar]</span><span class="p">))){</span>
</span></span><span class="line"><span class="cl">        <span class="n">pal</span> <span class="o">&lt;-</span> <span class="nf">rep</span><span class="p">(</span><span class="n">pal</span><span class="p">,</span> <span class="nf">ceiling</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="nf">length</span><span class="p">(</span><span class="nf">unique</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">gvar]</span><span class="p">))</span> <span class="o">/</span> <span class="nf">length</span><span class="p">(</span><span class="n">pal</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">pal</span> <span class="o">&lt;-</span> <span class="n">pal</span><span class="nf">[seq_len</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="nf">unique</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">gvar]</span><span class="p">)))</span><span class="n">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">p</span> <span class="o">&lt;-</span> <span class="nf">ggplot</span><span class="p">(</span><span class="n">df</span><span class="p">,</span> <span class="nf">aes</span><span class="p">(</span><span class="nf">eval</span><span class="p">(</span><span class="nf">parse</span><span class="p">(</span><span class="n">text</span><span class="o">=</span><span class="n">xvar</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">                   <span class="nf">eval</span><span class="p">(</span><span class="nf">parse</span><span class="p">(</span><span class="n">text</span><span class="o">=</span><span class="n">yvar</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">                   <span class="n">color</span><span class="o">=</span><span class="nf">eval</span><span class="p">(</span><span class="nf">parse</span><span class="p">(</span><span class="n">text</span><span class="o">=</span><span class="n">gvar</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">                   <span class="n">fill</span><span class="o">=</span><span class="nf">eval</span><span class="p">(</span><span class="nf">parse</span><span class="p">(</span><span class="n">text</span><span class="o">=</span><span class="n">gvar</span><span class="p">))))</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">        <span class="nf">geom_area</span><span class="p">(</span><span class="n">alpha</span><span class="o">=</span><span class="m">0.25</span><span class="p">,</span> <span class="n">position</span><span class="o">=</span><span class="s">&#34;stack&#34;</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">        <span class="nf">theme_hc</span><span class="p">()</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">        <span class="nf">scale_fill_manual</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">guide</span><span class="o">=</span><span class="nf">guide_legend</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="n">gvar</span><span class="p">),</span> <span class="n">values</span><span class="o">=</span><span class="n">pal</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">        <span class="nf">scale_color_manual</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">guide</span><span class="o">=</span><span class="nf">guide_legend</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="n">gvar</span><span class="p">),</span> <span class="n">values</span><span class="o">=</span><span class="n">pal</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">        <span class="nf">theme</span><span class="p">(</span><span class="n">axis.ticks</span><span class="o">=</span><span class="nf">element_line</span><span class="p">(</span><span class="n">linetype</span><span class="o">=</span><span class="m">0</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">              <span class="n">legend.position</span><span class="o">=</span><span class="n">legend.position</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="n">legend.direction</span><span class="o">=</span><span class="s">&#34;horizontal&#34;</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">        <span class="nf">xlab</span><span class="p">(</span><span class="n">xlab</span><span class="p">)</span> <span class="o">+</span> <span class="nf">ylab</span><span class="p">(</span><span class="n">ylab</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nf">if </span><span class="p">(</span><span class="nf">inherits</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">xvar]</span><span class="p">,</span> <span class="nf">c</span><span class="p">(</span><span class="s">&#34;POSIXt&#34;</span><span class="p">,</span> <span class="s">&#34;Date&#34;</span><span class="p">)))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">p</span> <span class="o">&lt;-</span> <span class="n">p</span> <span class="o">+</span> <span class="nf">scale_x_date</span><span class="p">(</span><span class="n">breaks</span><span class="o">=</span><span class="n">breaks</span><span class="p">,</span> <span class="n">labels</span><span class="o">=</span><span class="n">labels</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">            <span class="nf">labs</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="n">title</span><span class="p">,</span> <span class="n">subtitle</span><span class="o">=</span><span class="nf">paste</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                <span class="nf">format</span><span class="p">(</span><span class="nf">min</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">xvar]</span><span class="p">),</span> <span class="s">&#34;%Y-%m&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                <span class="nf">format</span><span class="p">(</span><span class="nf">max</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">xvar]</span><span class="p">),</span> <span class="s">&#34;%Y-%m&#34;</span><span class="p">),</span> <span class="n">sep</span><span class="o">=</span><span class="s">&#34;~&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span><span class="n">else</span> <span class="nf">if </span><span class="p">(</span><span class="nf">is.numeric</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">xvar]</span><span class="p">)){</span>
</span></span><span class="line"><span class="cl">        <span class="n">p</span> <span class="o">&lt;-</span> <span class="n">p</span> <span class="o">+</span> <span class="nf">scale_x_continuous</span><span class="p">(</span><span class="n">breaks</span><span class="o">=</span><span class="n">breaks</span><span class="p">,</span> <span class="n">labels</span><span class="o">=</span><span class="n">labels</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">            <span class="nf">labs</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="n">title</span><span class="p">,</span> <span class="n">subtitle</span><span class="o">=</span><span class="nf">paste</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                <span class="nf">min</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">xvar]</span><span class="p">),</span> <span class="nf">max</span><span class="p">(</span><span class="n">df[</span><span class="p">,</span><span class="n">xvar]</span><span class="p">),</span> <span class="n">sep</span><span class="o">=</span><span class="s">&#34;~&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span><span class="n">else</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">p</span> <span class="o">&lt;-</span> <span class="n">p</span> <span class="o">+</span> <span class="nf">scale_x_discrete</span><span class="p">(</span><span class="n">breaks</span><span class="o">=</span><span class="n">breaks</span><span class="p">,</span> <span class="n">labels</span><span class="o">=</span><span class="n">labels</span><span class="p">)</span> <span class="o">+</span>
</span></span><span class="line"><span class="cl">            <span class="nf">labs</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="n">title</span><span class="p">,</span> <span class="n">subtitle</span><span class="o">=</span><span class="s">&#34;&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="n">p</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>利用这个函数，只要来个数据框，就能出图。此外也不失灵活性，部分美学效果可以自定义调整。</p>
<p><a href="/post/infectdis_stat3/">待续</a></p>
<hr>
<!-- {% raw %} -->
<figure class="center"><img src="https://gh-1251443721.cos.ap-chengdu.myqcloud.com/QRcode.jpg"
         alt="扫码关注" width="30%"/><figcaption>
            <h4>扫码关注我的公众号</h4>
        </figcaption>
</figure>
<!-- {% endraw %} -->
    </div>

    <div class="post-copyright">
  <p class="copyright-item">
    <span class="item-title">文章作者</span>
    <span class="item-content">迷幻主义搬砖号子</span>
  </p>
  <p class="copyright-item">
    <span class="item-title">上次更新</span>
    <span class="item-content">
        2021-05-09
        <a href="https://github.com/madlogos/hugo-blog.git/commit/f3e8c5ae54f54c3eea5e759b3bce5a3facc97c88" title="changes on 2021年 5月 9日 星期日 21时28分26秒 CST">(f3e8c5a)</a>
    </span>
  </p>
  <p class="copyright-item">
      <span class="item-title">原始文档</span>
      <span class="item-content"><a class="link-to-markdown" href="https://madlogos.github.io/post/infectdis_stat2/index.md" target="_blank">查看本文 Markdown 版本 »</a></span>
    </p>
  <p class="copyright-item">
    <span class="item-title">许可协议</span>
    <span class="item-content"><a rel="license noopener" href="https://creativecommons.org/licenses/by-nc-nd/4.0/" target="_blank">CC BY-NC-ND 4.0</a></span>
  </p>
</div>
<div class="post-reward">
  <input type="checkbox" name="reward" id="reward" hidden />
  <label class="reward-button" for="reward">赞赏支持</label>
  <div class="qr-code">
    
    <label class="qr-code-image" for="reward">
        <img class="image" src="/img/reward/wechat.png">
        <span>微信打赏</span>
      </label>
    <label class="qr-code-image" for="reward">
        <img class="image" src="/img/reward/alipay.png">
        <span>支付宝打赏</span>
      </label>
  </div>
</div><footer class="post-footer">
      <div class="post-tags">
          <a href="/tags/%E4%BC%A0%E6%9F%93%E7%97%85/">传染病</a>
          <a href="/tags/%E7%96%AB%E6%83%85%E6%8A%A5%E5%91%8A/">疫情报告</a>
          <a href="/tags/rvest/">rvest</a>
          </div>
      <nav class="post-nav">
        <a class="prev" href="/post/infectdis_stat3/">
            <i class="iconfont icon-left"></i>
            <span class="prev-text nav-default">一次不太成功的搬砖（下）：rvest爬取法定传染病疫情月报数据</span>
            <span class="prev-text nav-mobile">上一篇</span>
          </a>
        <a class="next" href="/post/infectdis_stat1/">
            <span class="next-text nav-default">一次不太成功的搬砖（上）：爬取法定传染病疫情月报数据</span>
            <span class="next-text nav-mobile">下一篇</span>
            <i class="iconfont icon-right"></i>
          </a>
      </nav>
    </footer>
  </article>
        </div>
        <div id="disqus_thread"></div>
    <script type="text/javascript">
    (function() {
      
      
      if (window.location.hostname === 'localhost') return;

      var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
      var disqus_shortname = 'madlogos-gh';
      dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
      (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
    </script>
    <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>

  

  

      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="social-links">
      <a href="mailto:madlogos@gmail.com" class="iconfont icon-email" title="email"></a>
      <a href="https://stackoverflow.com/users/5455754/madlogos?tab=profile" class="iconfont icon-stack-overflow" title="stack-overflow"></a>
      <a href="https://twitter.com/madlogos" class="iconfont icon-twitter" title="twitter"></a>
      <a href="https://www.facebook.com/madlogos" class="iconfont icon-facebook" title="facebook"></a>
      <a href="http://www.linkedin.com/in/yiying-wang/" class="iconfont icon-linkedin" title="linkedin"></a>
      <a href="https://plus.google.com/&#43;%E6%B1%AA%E8%BD%B6%E9%A2%96madlogos" class="iconfont icon-google" title="google"></a>
      <a href="http://github.com/madlogos" class="iconfont icon-github" title="github"></a>
      <a href="https://weibo.com/madlogos/" class="iconfont icon-weibo" title="weibo"></a>
      <a href="https://www.zhihu.com/people/madlogos/" class="iconfont icon-zhihu" title="zhihu"></a>
      <a href="https://www.douban.com/people/Jandeaux/" class="iconfont icon-douban" title="douban"></a>
      <a href="https://jandeaux.tumblr.com" class="iconfont icon-tumblr" title="tumblr"></a>
      <a href="https://www.instagram.com/jandeaux/" class="iconfont icon-instagram" title="instagram"></a>
      <a href="https://gitlab.com/madlogos" class="iconfont icon-gitlab" title="gitlab"></a>
      <a href="https://space.bilibili.com/384080442" class="iconfont icon-bilibili" title="bilibili"></a>
  <a href="https://madlogos.github.io/index.xml" type="application/rss+xml" class="iconfont icon-rss" title="rss"></a>
</div>

<div class="copyright">
  <span class="power-by">
    由 <a class="hexo-link" href="https://gohugo.io">Hugo</a> 强力驱动
  </span>
  <span class="division">|</span>
  <span class="theme-info">
    主题 - 
    <a class="theme-link" href="https://github.com/olOwOlo/hugo-theme-even">Even</a>
  </span>

  <div class="busuanzi-footer">
    <span id="busuanzi_container_site_pv"> 本站总访问量 <span id="busuanzi_value_site_pv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 次 </span>
      <span class="division">|</span>
    <span id="busuanzi_container_site_uv"> 本站总访客数 <span id="busuanzi_value_site_uv"><img src="/img/spinner.svg" alt="spinner.svg"/></span> 人 </span>
  </div>

  <span class="copyright-year">
    &copy; 
    2017 - 
    2022
    
    <span class="author">madlogos</span>
  </span>
</div>

    </footer>

    <div class="back-to-top" id="back-to-top">
      <i class="iconfont icon-up"></i>
    </div>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/slideout@1.0.1/dist/slideout.min.js" integrity="sha256-t+zJ/g8/KXIJMjSVQdnibt4dlaDxc9zXr/9oNPeWqdg=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js" integrity="sha256-yt2kYMy0w8AbtF89WXb2P1rfjcP/HTHLT7097U8Y5b8=" crossorigin="anonymous"></script><script></script><script src="https://cdn.jsdelivr.net/npm/raphael@2.3.0/raphael.min.js" integrity="sha256-TabprKdeNXbSesCWLMrcbWSDzUhpAdcNPe5Q53rn9Yg=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/flowchart.js@1.12.1/release/flowchart.min.js" integrity="sha256-ANSuVJkHZftRURALG24omixaZG+Sb51/+JY6EDa7MdE=" crossorigin="anonymous"></script><script></script><script src="https://cdn.jsdelivr.net/npm/webfontloader@1.6.28/webfontloader.js" integrity="sha256-4O4pS1SH31ZqrSO2A/2QJTVjTPqVe+jnYgOWUVr7EEc=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/snapsvg@0.5.1/dist/snap.svg-min.js" integrity="sha256-oI+elz+sIm+jpn8F/qEspKoKveTc5uKeFHNNVexe6d8=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/underscore@1.10.2/underscore-min.js" integrity="sha256-av1TvywtZ4ZqyCj/6HdtCHSJdn80HAzTgEBTJt/O8uc=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/@rokt33r/js-sequence-diagrams@2.0.6-2/dist/sequence-diagram-min.js" integrity="sha256-eadHf9g1REH9Wvp2FLV/D9vKNvQUFKuVPgWFvmMQxBE=" crossorigin="anonymous"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@rokt33r/js-sequence-diagrams@2.0.6-2/dist/sequence-diagram-min.css" integrity="sha256-On01v36B8LRDuL2tqhqs7Gb3Cm/NIpsLFy4OarOodUA=" crossorigin="anonymous">



<script type="text/javascript" src="/js/main.min.4ae89da218555efa0e7093a20b92017d2e1202b66fff9fc2edf4cb8d44b44c6e.js"></script>
  <script type="text/javascript">
    window.MathJax = {
      tex: {
        inlineMath: [['$','$'], ['\\(','\\)']],
        tags: 'ams',
        }
    };
  </script>
  <script async src="https://cdn.jsdelivr.net/npm/mathjax@3.0.5/es5/tex-mml-chtml.js" integrity="sha256-HGLuEfFcsUJGhvB8cQ8nr0gai9EucOOaIxFw7qxmd+w=" crossorigin="anonymous"></script>


<script type="application/javascript">
var doNotTrack = false;
if (!doNotTrack) {
	window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
	ga('create', 'UA-68964085-2', 'auto');
	ga('set', 'anonymizeIp', true);
	ga('send', 'pageview');
}
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>
<script id="baidu_analytics">
  var _hmt = _hmt || [];
  (function() {
    if (window.location.hostname === 'localhost') return;
    var hm = document.createElement("script"); hm.async = true;
    hm.src = "https://hm.baidu.com/hm.js?f221e23428218df65adeefe00f85e7ed";
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(hm, s);
  })();
</script>

<script id="baidu_push">
  (function(){
    if (window.location.hostname === 'localhost') return;
    var bp = document.createElement('script'); bp.async = true;
    var curProtocol = window.location.protocol.split(':')[0];
    if (curProtocol === 'https') {
      bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
    }
    else {
      bp.src = 'http://push.zhanzhang.baidu.com/push.js';
    }
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(bp, s);
  })();
</script>


<script src="/js/custom.js"></script>


</body>
</html>
